local _, playerClass = UnitClass("player")
if playerClass ~= "ROGUE" and playerClass ~= "WARRIOR" and playerClass ~= "HUNTER" and playerClass ~= "DRUID" and playerClass ~= "PALADIN" and playerClass ~= "SHAMAN" and playerClass ~= "DEATHKNIGHT" then return end
local playerHybrid = (playerClass == "DRUID") or (playerClass == "PALADIN") or (playerClass == "SHAMAN") or (playerClass == "DEATHKNIGHT")

--Libraries
DrDamage = DrDamage or AceLibrary:HasInstance("FuBarPlugin-2.0") and AceLibrary("AceAddon-2.0"):new("AceConsole-2.0", "AceEvent-2.0", "AceDB-2.0", "AceHook-2.1", "FuBarPlugin-2.0") or AceLibrary("AceAddon-2.0"):new("AceConsole-2.0", "AceEvent-2.0", "AceDB-2.0", "AceHook-2.1")
local L = AceLibrary("AceLocale-2.2"):new("DrDamage")
local GT = LibStub:GetLibrary("LibGratuity-3.0")
local DrDamage = DrDamage

--General
local settings
local type = type
local next = next
local pairs = pairs
local ipairs = ipairs
local tonumber = tonumber
local math_abs = math.abs
local math_floor = math.floor
local math_ceil = math.ceil
local math_min = math.min
local math_max = math.max
local math_modf = math.modf
local string_match = string.match
local string_gsub = string.gsub
local select = select

--Module
local GetSpellInfo = GetSpellInfo
local GetCritChance = GetCritChance
local GetRangedCritChance = GetRangedCritChance
local GetCombatRatingBonus = GetCombatRatingBonus
local GetItemInfo = GetItemInfo
local GetInventoryItemLink = GetInventoryItemLink
local GetWeaponEnchantInfo = GetWeaponEnchantInfo
local GetComboPoints = GetComboPoints
local GetShieldBlock = GetShieldBlock
local GetShapeshiftForm = GetShapeshiftForm
local GetExpertise = GetExpertise
local GetArmorPenetration = GetArmorPenetration
local GetSpellBonusDamage = GetSpellBonusDamage
local GetSpellCritChance = GetSpellCritChance
local UnitRangedDamage = UnitRangedDamage
local UnitRangedAttack = UnitRangedAttack
local UnitDamage = UnitDamage
local UnitAttackSpeed = UnitAttackSpeed
local UnitAttackPower = UnitAttackPower
local UnitAttackBothHands = UnitAttackBothHands
local UnitRangedAttackPower = UnitRangedAttackPower
local UnitExists = UnitExists
local UnitPower = UnitPower
local UnitPowerMax = UnitPowerMax
local UnitPowerType = UnitPowerType
local UnitIsPlayer = UnitIsPlayer
local UnitDebuff = UnitDebuff
local UnitBuff = UnitBuff
local UnitName = UnitName
local UnitLevel = UnitLevel
local OffhandHasWeapon = OffhandHasWeapon
local IsEquippedItem = IsEquippedItem

--Module variables
local DrD_ClearTable, DrD_Round, DrD_MatchData, DrD_DmgCalc, DrD_BuffCalc
local spellInfo, PlayerAura, TargetAura, Consumables
local Calculation, SetBonuses

local function DrD_Set( n, setOnly )
	return function(v) 
		settings[n] = v
		if not setOnly and not DrDamage:IsEventScheduled("DrD_FullUpdate") then
			DrDamage:ScheduleEvent("DrD_FullUpdate", DrDamage.UpdateAB, 0.25, DrDamage)
		end
	end
end

if not playerHybrid then
	DrDamage.defaults = {}
end

DrDamage.defaults.HitCalc_M = false
DrDamage.defaults.TwoRoll_M = false
DrDamage.defaults.Dodge_M = false
DrDamage.defaults.Parry_M = false
DrDamage.defaults.Glancing_M = false
DrDamage.defaults.CritDepression_M = false
DrDamage.defaults.HitTarget_M = false
DrDamage.defaults.TargetLevel_M = 3
DrDamage.defaults.MitigationCalc_M = false
DrDamage.defaults.Armor_M = 0
DrDamage.defaults.Resilience_M = 0
DrDamage.defaults.ComboPoints_M = 0
DrDamage.defaults.DisplayType_M = "AvgTotal"
DrDamage.defaults.Coeffs_M = true
DrDamage.defaults.DispCrit_M = true
DrDamage.defaults.DispHit_M = true
DrDamage.defaults.AvgHit_M = true
DrDamage.defaults.AvgCrit_M = true
DrDamage.defaults.Ticks_M = true
DrDamage.defaults.Total_M = true
DrDamage.defaults.Extra_M = true
DrDamage.defaults.Next_M = true
DrDamage.defaults.DPS_M = true
DrDamage.defaults.DPM_M = true
		
function DrDamage:Melee_OnEnable()
	if self.Melee_Options then
		self:Melee_Options()
		self.Melee_Options = nil
	end
	if self.Melee_Data then
		self:Melee_Data()
		self.Melee_Data = nil
	end	
	if playerClass == "DEATHKNIGHT" then
		if settings["DisplayType_M"] == "DPM" or settings["DisplayType_M"] == "PowerCost" then
			settings["DisplayType_M"] = "AvgTotal"
		end
	end
	if settings.ABText then
		if playerClass == "HUNTER" then
			self:RegisterBucketEvent("UNIT_RANGEDDAMAGE", 1)
			self:UNIT_RANGEDDAMAGE(nil, true)
		end
		if playerClass == "DRUID" or playerClass == "ROGUE" then
			self:RegisterEvent("UNIT_COMBO_POINTS")
		end
		if playerClass == "WARRIOR" then
			self:RegisterBucketEvent("UNIT_RAGE", 2)
		end
		if playerClass == "DRUID" then
			self:RegisterBucketEvent("UNIT_ENERGY", 2)
		end
	end
	
	self:Melee_InventoryChanged(true, true, true)
	
	DrD_ClearTable = self.ClearTable
	DrD_Round = self.Round
	DrD_MatchData = self.MatchData
	DrD_BuffCalc = self.BuffCalc
	spellInfo = self.spellInfo
	PlayerAura = self.PlayerAura
	TargetAura = self.TargetAura
	Consumables = self.Consumables
	Calculation = self.Calculation
	SetBonuses = self.SetBonuses
end

function DrDamage:Melee_OnProfileEnable()
	settings = self.db.profile
end

function DrDamage:Melee_Options()
	local table
	
	if playerHybrid then
		self.options.args.Melee = { type = "group", name = L["Melee"], desc = L["Melee options."], order = 3, args = {} }
		table = self.options.args.Melee.args	
	else
		table = self.options.args
	end
	
	table.Calculation = {
		type = 'group', name = L["Calculation"], desc = L["Calculation options."], 
		args = {			
			HitCalc = {			
				type = 'toggle',
				name = L["Hit calculation"],
				desc = L["Hit calculation into averages."],
				order = 10,
				get = function() return settings["HitCalc_M"] end,
				set = DrD_Set("HitCalc_M"),
			},
			TwoRoll = {			
				type = 'toggle',
				name = L["Two roll calculation"],
				desc = L["Uses a two roll calculation for special melee/ranged attacks."],
				order = 15,
				get = function() return settings["TwoRoll_M"] end,
				set = DrD_Set("TwoRoll_M"),
			},			
			Dodge = {
				type = 'toggle',
				name = L["Dodge calculation"],
				desc = L["Dodge calculation into averages."],
				order = 20,
				get = function() return settings["Dodge_M"] end,
				set = DrD_Set("Dodge_M"),			
			},
			Parry = {
				type = 'toggle',
				name = L["Parry calculation"],
				desc = L["Parry calculation into averages."],
				order = 30,
				get = function() return settings["Parry_M"] end,
				set = DrD_Set("Parry_M"),			
			},
			Glancing = {
				type = 'toggle',
				name = L["Glancing blow calculation"],
				desc = L["Glancing blow calculation into averages."],
				order = 35,
				get = function() return settings["Glancing_M"] end,
				set = DrD_Set("Glancing_M"),			
			},
			CritDepression = {
				type = 'toggle',
				name = L["Crit depression calculation"],
				desc = L["Crit chance is reduced against higher level mobs."],
				order = 36,
				get = function() return settings["CritDepression_M"] end,
				set = DrD_Set("CritDepression_M"),			
			},
			HitTarget = {			
				type = 'toggle',
				name = L["Calculate by current target"],
				desc = L["Toggles calculation by target level. If nothing is targeted, the manually set level is used."],
				order = 40,
				get = function() return settings["HitTarget_M"] end,
				set = DrD_Set("HitTarget_M"),
			},
			TargetLevel = {
				type = 'range',
				name = L["Target level"],
				desc = L["Target level compared to your level. Set as 3 for boss calculation."],
				min = -10,
				max = 10,
				step = 1,
				order = 50,
				get = function() return settings["TargetLevel_M"] end,
				set = DrD_Set("TargetLevel_M"),
			},
			MitigationCalc = {
				type = 'toggle',
				name = L["Target mitigation calculation"],
				desc = L["Uses known boss armor and manually set mitigation values for calculation."],
				order = 60,
				get = function() return settings["MitigationCalc_M"] end,
				set = DrD_Set("MitigationCalc_M"),
			},			
			Armor = {
				type = 'range',
				name = L["Target armor"],
				desc = L["Estimated target armor for non-boss enemies. Compare to tooltip numbers for desired mitigation."],
				min = 0,
				max = 50000,
				step = 1,
				order = 80,
				get = function() return settings["Armor_M"] end,
				set = DrD_Set("Armor_M"),
			},
			Resilience = {
				type = 'range',
				name = L["Target resilience"],
				min = 0,
				max = 1500,
				step = 1,
				desc = L["Input your target's resilience."],
				order = 90,
				get = function() return settings["Resilience_M"] end,
				set = DrD_Set("Resilience_M"),	
			},
			ComboPoints = {
				type = 'range',
				name = L["Combo points"],
				desc = L["Manually set the amount of calculated combo points. When 0 is selected, the calculation is based on the current amount."],
				min = 0,
				max = 5,
				step = 1,
				order = 150,
				get = function() return settings["ComboPoints_M"] end,
				set = DrD_Set("ComboPoints_M"),
			},			
		},
	}
	table.ActionBar = {
		type = 'group', name = L["Actionbar"], desc = L["Actionbar options."],
		args = {
			DisplayType = {
				type = "text",
				name = L["Display"],
				desc = L["Choose what to display on the actionbar."],
				validate =  { 
					["AvgTotal"] = L["AvgTotal"], 
					["Avg"] = L["Avg"], 
					["Min"] = L["Min"], 
					["Max"] = L["Max"], 
					["AvgCrit"] = L["AvgCrit"], 
					["MinCrit"] = L["MinCrit"], 
					["MaxCrit"] = L["MaxCrit"], 
					["DPM"] = L["DPM"], 
					["PowerCost"] = L["PowerCost"],
				},
				get =  function() return settings["DisplayType_M"] end,
				set =  DrD_Set("DisplayType_M"),
				order = 70,
			},
		},
	}
	table.Tooltip = {
		type = 'group', name = L["Tooltip"], desc = L["Tooltip options."], 
		args = {					
			Coeffs = {
				type = 'toggle',
				name = L["Show coefficients"],
				desc = L["Show coefficients"],
				order = 53,
				get = function() return settings["Coeffs_M"] end,
				set = DrD_Set("Coeffs_M", true),
			},				
			DispCrit = {
				type = 'toggle',
				name = L["Show crit %"],
				desc = L["Show crit %"],
				order = 54,
				get = function() return settings["DispCrit_M"] end,
				set = DrD_Set("DispCrit_M", true),
			},
			DispHit = {
				type = 'toggle',
				name = L["Show hit %"],
				desc = L["Show hit %"],
				order = 56,
				get = function() return settings["DispHit_M"] end,
				set = DrD_Set("DispHit_M", true),
			},				
			AvgHit = {
				type = 'toggle',
				name = L["Show avg and hit range"],
				desc = L["Show avg and hit range"],
				order = 58,
				get = function() return settings["AvgHit_M"] end,
				set = DrD_Set("AvgHit_M", true),
			},
			AvgCrit = {
				type = 'toggle',
				name = L["Show avg crit and crit range"],
				desc = L["Show avg crit and crit range"],
				order = 60,
				get = function() return settings["AvgCrit_M"] end,
				set = DrD_Set("AvgCrit_M", true),
			},
			Ticks = {
				type = 'toggle',
				name = L["Show per tick"],
				desc = L["Show per tick"],
				order = 62,
				get = function() return settings["Ticks_M"] end,
				set = DrD_Set("Ticks_M", true),
			},
			Total = {
				type = 'toggle',
				name = L["Show avg total"],
				desc = L["Show avg total"],
				order = 64,
				get = function() return settings["Total_M"] end,
				set = DrD_Set("Total_M", true),
			},				
			Extra = {
				type = 'toggle',
				name = L["Show additional effects"],
				desc = L["Show additional effects"],
				order = 66,
				get = function() return settings["Extra_M"] end,
				set = DrD_Set("Extra_M", true),
			},
			Next = {
				type = 'toggle',
				name = L["Show stat increase values"],
				desc = L["Show stat increase values"],
				order = 68,
				get = function() return settings["Next_M"] end,
				set = DrD_Set("Next_M", true),
			},
			DPS = {
				type = 'toggle',
				name = L["Show DPS"],
				desc = L["Show DPS"],
				order = 70,
				get = function() return settings["DPS_M"] end,
				set = DrD_Set("DPS_M", true),
			},
			DPM = {
				type = 'toggle',
				name = L["Show damage per power"],
				desc = L["Show damage per power"],
				order = 72,
				get = function() return settings["DPM_M"] end,
				set = DrD_Set("DPM_M", true),
			},
		},
	}
	if playerClass == "DEATHKNIGHT" then
		local types = table.ActionBar.args.DisplayType.validate
		types["PowerCost"] = nil
		types["DPM"] = nil
	end
end

function DrDamage:Melee_Data()
	self.spellInfo[GetSpellInfo(6603)] = {
		["Name"] = "Attack",
		[0] = { AutoAttack = true, Melee = true, WeaponDamage = 1, NoNormalization = true },
		[1] = { 0 },
	}
end

local lastRage = 0
local execute = GetSpellInfo(5308)
function DrDamage:UNIT_RAGE( units )
	if units["player"] then
		local rage = UnitPower("player",1)
		if math_abs(rage - lastRage) >= 10 then
			lastRage = rage
			self:UpdateAB(execute)
		end
	end
end

local lastEnergy = 0
local fbite = GetSpellInfo(22568)
function DrDamage:UNIT_ENERGY( units )
	if units["player"] then
		local energy = UnitPower("player",3)
		local max = UnitPowerMax("player",3)
		if math_abs(energy - lastEnergy) >= 20 or (energy == max and lastEnergy ~= max) then
			lastEnergy = energy
			self:UpdateAB(fbite)
		end
	end
end

function DrDamage:UNIT_COMBO_POINTS( unit )
	if settings.ComboPoints_M == 0 and unit == "player" then
		self:CancelScheduledEvent("DrD_FullUpdate")
		self:ScheduleEvent("DrD_FullUpdate", self.UpdateAB, 0.1, self)
	end
end

local oldammo
local ammoDmg = 0
function DrDamage:UNIT_RANGEDDAMAGE(unit, first)
	if first or unit["player"] then
		local newammo = GetInventoryItemLink("player", 0)
		if newammo ~= oldammo then
			oldammo = newammo
			if GT:SetInventoryItem("player", 0) then
				for i = 3, GT:NumLines() do
					local line = GT:GetLine(i)
					line = line and string_match(line,"%d+")			
					if line then
						ammoDmg = tonumber((string_gsub(line,",","%."))) or 0
						break
					end
				end
			else
				ammoDmg = 0
			end
			if not self:IsEventScheduled("DrD_FullUpdate") and not first then
				self:ScheduleEvent("DrD_FullUpdate", self.UpdateAB, 0.5, self)
			end
		end
	end
end

local oldValues = 0
function DrDamage:Melee_CheckBaseStats()
	local newValues = 
	GetCombatRatingBonus(6)
	+ GetCombatRatingBonus(7)
	+ GetCombatRatingBonus(18)
	+ GetCombatRatingBonus(19)	
	+ self:GetAP() 
	+ self:GetRAP() 
	+ GetCritChance()
	+ GetRangedCritChance()
	+ UnitDamage("player")
	+ select(3,UnitDamage("player"))
	+ UnitRangedDamage("player")
	+ select(2,UnitRangedDamage("player"))
	+ GetShieldBlock()

	if newValues ~= oldValues then
		oldValues = newValues
		return true
	end

	return false	
end

local mhType, ohType, rgType
function DrDamage:GetWeaponType()
	return mhType, ohType, rgType
end

local mhSpeed, mhMin, mhMax, ohSpeed, rgSpeed, rgMin, rgMax, _
function DrDamage:Melee_InventoryChanged(mhslot, ohslot, rangedslot)
	if mhslot then
		if GT:SetInventoryItem("player", 16) then
			for i = 3, GT:NumLines() do
				local line = GT:GetLine(i,true)
				line = line and string_match(line,"%d.%d+")
				if line then
					mhSpeed = tonumber((string_gsub(line,",","%.")))
					mhMin, mhMax = string_match(GT:GetLine(i), "(%d+)[^%d]+(%d+)")
					mhMin = tonumber(mhMin) or 0
					mhMax = tonumber(mhMax) or 0
					break
				end
			end
			mhType = select(7,GetItemInfo(GetInventoryItemLink("player", 16)))
		else
			mhType = nil
			mhMin, mhMax = 0, 0
			mhSpeed = UnitAttackSpeed("player")
		end
	end
	if ohslot then
		if GT:SetInventoryItem("player", 17) then
			for i = 3, GT:NumLines() do
				local line = GT:GetLine(i,true)
				line = line and string_match(line,"%d.%d+")
				if line then
					ohSpeed = tonumber((string_gsub(line,",","%.")))
					break					
				end
			end
			ohType = select(7,GetItemInfo(GetInventoryItemLink("player", 17)))
		else
			ohType = nil
			_, ohSpeed = UnitAttackSpeed("player")
		end
	end
	if rangedslot then
		if GT:SetInventoryItem("player", 18) then
			for i = 3, GT:NumLines() do
				local line = GT:GetLine(i,true)
				line = line and string_match(line,"%d.%d+")			
				if line then
					rgSpeed = tonumber((string_gsub(line,",","%.")))
					rgMin, rgMax = string_match(GT:GetLine(i), "(%d+)[^%d]+(%d+)")
					rgMin = tonumber(rgMin) or 0
					rgMax = tonumber(rgMax) or 0
					break
				end
				
				
			end
			rgType = select(7,GetItemInfo(GetInventoryItemLink("player", 18)))
		else
			rgType = nil
			rgMin, rgMax = 0, 0
			rgSpeed = UnitRangedDamage("player")
		end
	end	
end

function DrDamage:GetMainhandBase()
	return mhMin, mhMax
end

function DrDamage:GetRangedBase()
	return rgMin, rgMax
end

function DrDamage:GetAmmoDmg()
	return ammoDmg
end

function DrDamage:GetWeaponSpeed()
	return mhSpeed, ohSpeed, rgSpeed
end

function DrDamage:GetAP()
	local baseAP, posBuff, negBuff = UnitAttackPower("player")
	return baseAP + posBuff + negBuff
end

function DrDamage:GetRAP()
	local baseAP, posBuff, negBuff = UnitRangedAttackPower("player")
	return baseAP + posBuff + negBuff	
end

local normalizationTable = {
	--[[
	"Daggers"
	"One-Handed Axes"
	"One-Handed Maces"
	"One-Handed Swords"
	"Fist Weapons"
	"Two-Handed Axes"
	"Two-Handed Maces"
	"Two-Handed Swords"
	"Polearms"
	"Staves"
	"Fishing Poles"
	--]]	
	[GetSpellInfo(1180)] = 1.7,
	[GetSpellInfo(196)] = 2.4,
	[GetSpellInfo(198)] = 2.4,
	[GetSpellInfo(201)] = 2.4,
	[GetSpellInfo(15590)] = 2.4,	
	[GetSpellInfo(197)] = 3.3,
	[GetSpellInfo(199)] = 3.3,
	[GetSpellInfo(202)] = 3.3,	
	[GetSpellInfo(200)] = 3.3,
	[GetSpellInfo(227)] = 3.3,
	[GetSpellInfo(7738)] = 3.3,
}
function DrDamage:GetNormM() 
	return mhType and normalizationTable[mhType] or 2, ohType and normalizationTable[ohType] or 2
end

function DrDamage:WeaponDamage(calculation, wspd)
	local min, max, omin, omax, mod
	local spd, normM, normM_O
	local mh, oh = self:GetNormM()
	local AP = calculation.AP
	local baseAP
	
	if calculation.ranged then
		_, min, max, _, _, mod = UnitRangedDamage("player")
		spd = rgSpeed
		normM = wspd and spd or 2.8
		baseAP = self:GetRAP()
	else
		min, max, omin, omax, _, _, mod = UnitDamage("player")
		baseAP = self:GetAP()
		
		if calculation.requiresForm then
			if calculation.requiresForm == 1 then
				spd = 2.5
				normM = 2.5
			elseif calculation.requiresForm == 3 then
				spd = 1
				normM = 1
			end
		else
			spd = mhSpeed
			normM = wspd and mhSpeed or mh
			normM_O = wspd and ohSpeed or oh
		end
	end
	
	local bonus, obonus = normM / 14
	mod = calculation.wDmgM * mod
	
	min = (min/(mod) - (baseAP / 14) * spd + bonus * AP) * calculation.wDmgM
	max = (max/(mod) - (baseAP / 14) * spd + bonus * AP) * calculation.wDmgM
	
	if OffhandHasWeapon() and omin and omax and ohSpeed then
		obonus = normM_O / 14
		omin = (omin/(calculation.offHdmgM * mod) - (baseAP / 14) * ohSpeed + obonus * AP) * calculation.offHdmgM * calculation.wDmgM
		omax = (omax/(calculation.offHdmgM * mod) - (baseAP / 14) * ohSpeed + obonus * AP) * calculation.offHdmgM * calculation.wDmgM
	end
	
	return min, max, omin, omax, bonus, obonus
end

function DrDamage:GetRageGain( avg, calculation )
    	local level = UnitLevel("player")
	local avgFactor = 3.5 + 3.5 * (calculation.critPerc/100)
	local conversion = 0.0091107836 * level * level + 3.225598133 * level + 4.2652911
	return (3.75 * (avg / conversion) + 0.5 * (mhSpeed * avgFactor))
end
	
function DrDamage:GetMeleeHit(ranged, unarmed)
	local _, playerLevel, targetLevel, boss = DrDamage:GetLevels()
	local skill, skillO, hit, hitO
	
	if not settings.HitTarget_M or not UnitExists("target") then
		targetLevel = playerLevel + settings.TargetLevel_M
		if settings.TargetLevel_M == 3 and playerLevel >= 70 then
			boss = true
		end
	end
	if ranged then
		hit = 95 + GetCombatRatingBonus(7)
		skill = (rgType == "None") and math_max(0,targetLevel * 5 - playerLevel * 5) or math_max(0,targetLevel * 5 - UnitRangedAttack("player"))
	else
		hit = 95 + GetCombatRatingBonus(6)
		hitO = 95 + GetCombatRatingBonus(6)
		if unarmed or (playerClass == "DRUID" and GetShapeshiftForm() > 0) or settings.HitTarget_M and UnitIsPlayer("target") then
			skill = math_max(0,targetLevel * 5 - (playerLevel * 5))
			skillO = skill
		else
			local mskill, _, oskill = UnitAttackBothHands("player")
			skill = (mhType == "None") and math_max(0,targetLevel * 5 - playerLevel * 5) or math_max(0,targetLevel * 5 - mskill)
			skillO = (ohType == "None") and math_max(0,targetLevel * 5 - (playerLevel * 5)) or math_max(0,targetLevel * 5 - oskill)
		end
	end

	if skill <= 10 then
		hit = hit - skill * 0.04 
	else
		hit = hit - 1 - (skill - 10) * 0.4
	end
	if skillO then
		if skillO <= 10 then
			hitO = hitO - skillO * 0.04
		else
			hitO = hitO - 1 - (skillO - 10) * 0.4
		end
	end

	return hit, hitO, boss, skill, skillO
end

--Static tables
local powerTypes = { [0] = L["Mana"], [1] = L["Rage"], [3] = L["Energy"] }
local schoolTable = { ["Holy"] = 2, ["Fire"] = 3, ["Nature"] = 4, ["Frost"] = 5, ["Shadow"] = 6, ["Arcane"] = 7 }

--Temporary tables
local calculation = {}
local ActiveAuras = {}
local BuffTalentRanks = {}
local CalculationResults = {}

function DrDamage:MeleeCalc( name, rank, tooltip, modify, debug )
	if not spellInfo or not name then return end
	if not rank then
		_, rank = GetSpellInfo(name)
	elseif tonumber(rank) and GetSpellInfo(name) then
		rank = string_gsub(select(2,GetSpellInfo(name)),"%d+", rank)
	end
	
	local baseAction = spellInfo[name][0]
	
	local action, actionName, actionTalents
	
	if type(baseAction) == "function" then
		baseAction, action, actionName = baseAction()
		actionTalents = spellInfo[actionName]["Talents"]
	else
		action = spellInfo[name][(rank and tonumber(string_match(rank,"%d+"))) or 1]
		actionName = spellInfo[name]["Name"]
		actionTalents = spellInfo[name]["Talents"]
	end
	
	if not action then return end
	
	DrD_ClearTable( calculation )

	calculation.offHdmgM = 0.5
	calculation.bDmgM = 1
	calculation.wDmgM = 1
	calculation.dmgM_Add = 0
	calculation.dmgM_dd_Add = 0
	calculation.dmgM_dd = 1
	calculation.dmgM_Extra = 1
	calculation.APBonus = baseAction.APBonus
	calculation.NoCrits = baseAction.NoCrits
	calculation.eDuration = action.eDuration or baseAction.eDuration or 0
	calculation.WeaponDamage = action.WeaponDamage or baseAction.WeaponDamage
	calculation.actionCost = select(4,GetSpellInfo(name,rank)) or 0
	calculation.powerType = select(6,GetSpellInfo(name,rank))
	calculation.cooldown = baseAction.Cooldown or 0
	calculation.castTime = action.castTime or baseAction.castTime
	calculation.requiresForm = baseAction.requiresForm
	calculation.hitPerc = 0
	calculation.name = name
	calculation.actionName = actionName
	calculation.Hits = baseAction.Hits
	calculation.freeCrit = 0
	calculation.bleedBonus = 1
	calculation.rageBonus = 1
	calculation.spellDmg = baseAction.SPBonus and GetSpellBonusDamage(2) or 0
	calculation.maxPower = baseAction.MaxPower
	calculation.extraPowerBonus = 0
	calculation.armorPen = 0
	calculation.armorMod = 0
	calculation.mitigation = 1
	calculation.expertise, calculation.expertise_O = GetExpertise()
	calculation.dmgBonus = 0
	calculation.E_eDuration = baseAction.E_eDuration
	calculation.E_canCrit = baseAction.E_canCrit	
	calculation.extra = action.Extra or 0
	calculation.extra_O = 0
	calculation.extraDamage = baseAction.ExtraDamage
	calculation.extraDamage_O = 0
	calculation.extraDamBonus = 0
	calculation.extraDamBonus_O = 0
	calculation.extraChance = 1
	calculation.extraChance_O = 1
	
	if settings.ComboPoints_M == 0 then
		calculation.Melee_ComboPoints = GetComboPoints("player")
	else
		calculation.Melee_ComboPoints = settings.ComboPoints_M
	end
	
	if not calculation.castTime then
		if baseAction.NextMelee then
			calculation.castTime = mhSpeed
		elseif playerClass == "ROGUE" or playerClass == "DRUID" and GetShapeshiftForm() == 3 then
			calculation.castTime = 1
		elseif baseAction.AutoShot then
			calculation.castTime = UnitRangedDamage("player")
		else
			calculation.castTime = 1.5
		end
	end
	
	if type( baseAction.School ) == "table" then
		calculation.school = baseAction.School[1]
		calculation.group = baseAction.School[2]
		calculation.subType = baseAction.School[3]
	else
		calculation.school = baseAction.School or "Physical"
	end
	
	--Checks
	calculation.physical = (calculation.school == "Physical") or (calculation.school == "Ranged") or (calculation.group == "Physical")
	calculation.unarmed = calculation.school == "Physical" and mhType == "None"
	
	if calculation.school == "Ranged" then
		calculation.ranged = true
		calculation.AP = self:GetRAP()
		calculation.critPerc = GetRangedCritChance()
		calculation.critM = 1
		calculation.dmgM = select(6,UnitRangedDamage("player"))
	else
		calculation.ranged = false
		calculation.AP = self:GetAP()
		calculation.critPerc = baseAction.SpellCrit and GetSpellCritChance(schoolTable[calculation.school] or 1) or GetCritChance()
		calculation.critM = baseAction.SpellCrit and 0.5 or 1
		calculation.dmgM = select(7,UnitDamage("player"))
	end
	if baseAction.DualAttack and OffhandHasWeapon() then
		calculation.bDmgM = calculation.bDmgM * 2
	end	
	
	local skill, skillO
	if baseAction.SpellHit then
		calculation.hit, calculation.hitO, calculation.boss = self:GetSpellHit()
	else
		calculation.hit, calculation.hitO, calculation.boss, skill, skillO = self:GetMeleeHit(calculation.ranged)
	end
	
	if not baseAction.SpellHit and not UnitIsPlayer("target") and not calculation.ranged and not baseAction.Unavoidable then
		--crit cap: 100 - 24 (glancing) - white miss chance (24% - hit%) - white dodge chance (6.5 - expertise%)
		if calculation.boss then
			calculation.dodge = 6.5 
			calculation.parry = 14.5
			if settings.CritDepression_M then
				calculation.critPerc = calculation.critPerc - 4.8
			end
			if baseAction.AutoAttack and settings.Glancing_M then
				calculation.glancing = 24
				calculation.glancingM = 0.75
			end
		else
			local _, playerLevel, targetLevel = self:GetLevels()
			targetLevel = settings.HitTarget_M and UnitExists("target") and targetLevel or (playerLevel + settings.TargetLevel_M)
			--TODO: How is dodge and parry chance determined?
			calculation.dodge = 5 + math_max(0, (targetLevel - playerLevel) * 0.5)
			calculation.parry = 5
			if settings.CritDepression_M then
				calculation.critPerc = calculation.critPerc - (skill/5) * 0.6 - math_min(1,math_floor(skill/11)) * 3
			end
			if baseAction.AutoAttack and settings.Glancing_M then
				--TODO: Improve this?
				calculation.glancing = math_min(100,math_max(0,(targetLevel - playerLevel + 1) * 6))
				calculation.glancingM = math_min(1,math_max(0, 1 - (targetLevel - playerLevel + 1) * 0.0625))
			end
		end
	end	
	
	calculation.minDam = action[1]
	calculation.maxDam = (action[2] or action[1])
	
	--RELICS
	if self.RelicSlot and self.RelicSlot[actionName] then
		local data = self.RelicSlot[actionName]
		local count = #data
		if count then
			for i = 1, count - 1, 2 do
				if data[i] and data[i+1] then
					if IsEquippedItem(data[i]) or debug then
						local modType = data["ModType"..((i+1)/2)]
						if not modType then
							calculation.minDam = calculation.minDam + data[i+1]
							calculation.maxDam = calculation.maxDam + data[i+1]
						elseif calculation[modType] then
							calculation[modType] = calculation[modType] + data[i+1]							
						end
					end
				end
			end
		end
	end	
	
	--TALENTS
	for i=1,#actionTalents do
		local talentValue = actionTalents[i]
		local modType = actionTalents["ModType" .. i]
		
		if calculation[modType] then
			if actionTalents["Multiply" .. i] then
				calculation[modType] = calculation[modType] * (1 + talentValue)
			else
				calculation[modType] = calculation[modType] + talentValue
			end
		elseif self.Calculation[modType] then
			self.Calculation[modType](calculation, talentValue, baseAction)
		else
			BuffTalentRanks[modType] = talentValue
		end				
	end
	
	--BUFF/DEBUFF CALCULATION
	if next(settings["PlayerAura"]) or debug then
		for buffName in pairs(debug and PlayerAura or settings["PlayerAura"]) do
			local aura = PlayerAura[buffName]
			if aura and not aura.Caster and not aura.Update then
				DrD_BuffCalc( aura, calculation, ActiveAuras, BuffTalentRanks, baseAction, buffName, nil, nil, nil, aura.Ranks )
			end
		end
	end
	if next(settings["TargetAura"]) or debug then
		for buffName in pairs(debug and TargetAura or settings["TargetAura"]) do
			local aura = TargetAura[buffName]
			if aura and not aura.Caster and not TargetAura[buffName].Update then
				DrD_BuffCalc( aura, calculation, ActiveAuras, BuffTalentRanks, baseAction, buffName, nil, nil, nil, aura.Ranks )
			end
		end
	end
	for index=1,40 do
		local buffName, rank, texture, apps = UnitBuff("player",index)
		if buffName then
			local aura = PlayerAura[buffName]
			if aura and not aura.Caster and not settings["PlayerAura"][buffName] and not aura.Update then
				DrD_BuffCalc( aura, calculation, ActiveAuras, BuffTalentRanks, baseAction, buffName, index, apps, texture, rank )
			end
		else break end
	end
	for index=1,40 do
		local buffName, rank, texture, apps = UnitDebuff("player",index)
		if buffName then
			local aura = PlayerAura[buffName]
			if aura and not aura.Caster and not settings["PlayerAura"][buffName] and not aura.Update then
				DrD_BuffCalc( aura, calculation, ActiveAuras, BuffTalentRanks, baseAction, buffName, index, apps, texture, rank )
			end
		else break end
	end
	for index=1,40 do
		local buffName, rank, texture, apps = UnitDebuff("target",index)
		if buffName then
			local aura = TargetAura[buffName]
			if aura and not aura.Caster and not settings["TargetAura"][buffName] and not aura.Update then
				DrD_BuffCalc( aura, calculation, ActiveAuras, BuffTalentRanks, baseAction, buffName, index, apps, texture, rank )
			end
		else break end
	end
	--Add manual selected consumables if not active
	if next(settings["Consumables"]) then
		for buffName in pairs(settings["Consumables"]) do
			if Consumables[buffName] then
				DrD_BuffCalc( Consumables[buffName], calculation, ActiveAuras, BuffTalentRanks, baseAction, buffName )
			end
		end
	end	
	
	--ADD CLASS SPECIFIC MODS
	if SetBonuses[playerClass] then
		SetBonuses[playerClass]( calculation, ActiveAuras, BuffTalentRanks, action, baseAction )
	end
	if Calculation[playerClass] then
		Calculation[playerClass]( calculation, ActiveAuras, BuffTalentRanks, action, baseAction )
	end	
	if SetBonuses[actionName] then
		SetBonuses[actionName]( calculation, ActiveAuras, BuffTalentRanks, action, baseAction )
	end
	if Calculation[actionName] then
		Calculation[actionName]( calculation, ActiveAuras, BuffTalentRanks, action, baseAction )
	end
	
	--CRIT MODIFIER CALCULATION (NEEDS TO BE DONE AFTER TALENTS)
	if baseAction.SpellCrit then
		calculation.critM = calculation.critM + 3 * self.Damage_critMBonus * calculation.critM
	else
		calculation.critM = calculation.critM + 2 * self.Damage_critMBonus * calculation.critM
	end
	
	--MITIGATION AND RESILIENCE CALCULATIONS
	calculation.dmgM_Extra = calculation.dmgM_Extra * (calculation.dmgM + calculation.dmgM_Add) * (not calculation.extraCrit and (baseAction.BleedExtra and calculation.bleedBonus or 1) or 1)
	calculation.dmgM = calculation.dmgM * calculation.dmgM_dd * (1 + calculation.dmgM_Add + calculation.dmgM_dd_Add)
	calculation.dmgM_Display = calculation.dmgM --* (calculation.WeaponDamage and calculation.wDmgM or 1)
	
	if settings.MitigationCalc_M and calculation.physical and (not calculation.group or calculation.group == "Physical") and not baseAction.eDuration and not baseAction.Bleed then
		if calculation.boss then
			--Armor / (Armor + (467.5 * AttackerLevel - 22167.5))
			--Wotlk bosses have 10643 (used to be 13083) armor
			--For a level 80 target, C=15232.5. For a level 83, C=16635.
			--Cap for level 83 target, (armor + 16635)/3
			local armor = 10643
			local cap = math_min(armor,(armor + 16635)/3) * (calculation.armorPen + GetArmorPenetration()/100)
			armor = armor - cap + calculation.armorMod
			calculation.mitigation = 1 - armor / (armor + (467.5 * UnitLevel("player") - 22167.5))
		elseif settings.Armor_M > 0 then
			local _, playerLevel, targetLevel = self:GetLevels()
			targetLevel = settings.HitTarget_M and UnitExists("target") and targetLevel or (playerLevel + settings.TargetLevel_M)	
			local armor = settings.Armor_M
			local C = (playerLevel < 60) and (400 + 85 * targetLevel) or (400 + 85 * targetLevel + 4.5 * 85 * (targetLevel-59))	
			local cap = math_min(armor,(armor + C)/3) * (calculation.armorPen + GetArmorPenetration()/100)
			armor = armor - cap + calculation.armorMod
			calculation.mitigation = (playerLevel < 60) and (1 -  armor / (armor + 400 + 85 * playerLevel)) or (1 - armor / (armor + (467.5 * playerLevel - 22167.5)))
		end
	end	
	if settings.Resilience_M > 0 then
		calculation.critPerc = math_max(0, calculation.critPerc - settings.Resilience_M / 82)
		calculation.critM = calculation.critM * math_max(2/3 - 1/(3 * calculation.critM), 1 - 0.044 * (settings.Resilience / 82))
		
		if calculation.E_eDuration then
			calculation.dmgM_Extra = calculation.dmgM_Extra * (1 - math_min(1, 0.01 * settings.Resilience_M / 82))
		end
		if baseAction.eDuration then
			calculation.dmgM = calculation.dmgM * math_min(0, 1 - 0.01 * settings.Resilience_M / 82)
		end
	end
	
	calculation.dmgM = calculation.dmgM * calculation.mitigation
	
	--AND NOW CALCULATE
	local avgTotal, text = DrD_DmgCalc( baseAction, action, false, false, tooltip )
	
	if tooltip and not calculation.zero then
		if not calculation.NoCrits then
			calculation.critPerc = calculation.critPerc + 1
			CalculationResults.NextCrit = DrD_Round( DrD_DmgCalc( baseAction, action, true ) - avgTotal, 2 )
			calculation.critPerc = calculation.critPerc - 1	
		end
		if calculation.APBonus or calculation.WeaponDamage then
			calculation.AP = calculation.AP + 100
			CalculationResults.NextAP = DrD_Round( DrD_DmgCalc( baseAction, action, true ) - avgTotal, 2 )
			calculation.AP = calculation.AP - 100
		end
		if baseAction.SPBonus then
			calculation.spellDmg = calculation.spellDmg + 10
			CalculationResults.NextSpellDmg = DrD_Round( DrD_DmgCalc( baseAction, action, true ) - avgTotal, 2 )
			calculation.spellDmg = calculation.spellDmg - 10
		end
		if not baseAction.Unresistable then
			local temp = settings.HitCalc_M and avgTotal or DrD_DmgCalc( baseAction, action, true, true )
			calculation.hitPerc = calculation.hitPerc + 1
			CalculationResults.NextHit = DrD_Round( DrD_DmgCalc( baseAction, action, true, true ) - temp, 2 )
			calculation.hitPerc = calculation.hitPerc - 1
			if settings.Dodge_M and calculation.dodge or settings.Parry_M and calculation.parry then
				calculation.expertise = calculation.expertise + 1
				CalculationResults.NextExpertise = DrD_Round( DrD_DmgCalc( baseAction, action, true ) - avgTotal, 2 )
			end
		end			
	end	
	
	DrD_ClearTable( BuffTalentRanks )
	DrD_ClearTable( ActiveAuras )
	
	return text, CalculationResults, debug and calculation
end

DrD_DmgCalc = function( baseAction, action, nextCalc, hitCalc, tooltip )
	local APmod, APoh = 0
	
	if DrDamage.DmgCalculation[calculation.actionName] then
		APmod = DrDamage.DmgCalculation[calculation.actionName]( calculation, ActiveAuras, BuffTalentRanks, action ) or 0
	end

	--Calculation
	local minDam = calculation.minDam * calculation.bDmgM
	local maxDam = calculation.maxDam * calculation.bDmgM
	local minDam_O, maxDam_O
	local minCrit, maxCrit
	local minCrit_O, maxCrit_O	
	local avgHit, avgHit_O
	local avgCrit,avgCrit_O
	local avgTotal
	local avgTotal_O = 0
	local eDuration = calculation.eDuration
	local baseDuration = action.eDuration or baseAction.eDuration
	local hitPerc = math_max(0,math_min(100, calculation.hit + calculation.hitPerc))
	local hitPerc_O = math_max(0,math_min(100, (calculation.hitO or calculation.hit) + calculation.hitPerc))
	local hitDW, hitDWO
	local hits = calculation.Hits
	local perHit, ticks
	local spd, ospd = UnitAttackSpeed("player")
	local baseAttack, avgTotalMod
	
	--CORE: Weapon Damage multiplier
	if calculation.WeaponDamage then
		local min, max
		min, max, minDam_O, maxDam_O, APmod, APoh = DrDamage:WeaponDamage(calculation, baseAction.NoNormalization)
		minDam = minDam + min * calculation.WeaponDamage
		maxDam = maxDam + max * calculation.WeaponDamage
	end
	--CORE: Off-hand attacks
	if OffhandHasWeapon() then
		if baseAction.AutoAttack or baseAction.DualAttack then
			minDam_O = minDam_O * calculation.WeaponDamage 
			maxDam_O = maxDam_O * calculation.WeaponDamage
			APmod = APmod + (APoh or 0)
		elseif baseAction.OffhandAttack then
			minDam = minDam_O * calculation.WeaponDamage
			maxDam = maxDam_O * calculation.WeaponDamage
			minDam_O = nil
			maxDam_O = nil
			APmod = (APoh or 0)
		end
		if baseAction.OffhandBonus then
			minDam_O = minDam_O + calculation.minDam * calculation.bDmgM
			maxDam_O = maxDam_O + calculation.maxDam * calculation.bDmgM
		end
	end
	--CORE: Combo point calculation
	if baseAction.ComboPoints then
		local cp = calculation.Melee_ComboPoints
		
		if cp > 0 then
			if action.PerCombo then
				minDam = minDam + action.PerCombo * ( cp - 1 )
				maxDam = maxDam + action.PerCombo * ( cp - 1 )
			end
			if baseAction.ExtraPerCombo then
				minDam = minDam + action.ExtraPerCombo * baseAction.ExtraPerCombo[cp]
				maxDam = maxDam + action.ExtraPerCombo * baseAction.ExtraPerCombo[cp]
			end
			if calculation.APBonus then
				if type( calculation.APBonus ) == "table" then
					minDam = minDam + calculation.APBonus[cp] * calculation.AP
					maxDam = maxDam + calculation.APBonus[cp] * calculation.AP
					APmod = APmod + calculation.APBonus[cp]
				else
					minDam = minDam + calculation.APBonus * cp * calculation.AP
					maxDam = maxDam + calculation.APBonus * cp * calculation.AP
					APmod = APmod + calculation.APBonus * cp
				end
			end
			if baseAction.DurationPerCombo then
				eDuration = calculation.eDuration + baseAction.DurationPerCombo * cp
				baseDuration = baseDuration + baseAction.DurationPerCombo * cp
			end
		else
			calculation.zero = true
		end
	else
	--CORE: AP and SP modifier for non-combo point abilities
		if calculation.APBonus then
			minDam = minDam + calculation.APBonus * calculation.AP
			maxDam = maxDam + calculation.APBonus * calculation.AP
			APmod = APmod + calculation.APBonus
		end
		if baseAction.SPBonus then
			minDam = minDam + baseAction.SPBonus * calculation.spellDmg
			maxDam = maxDam + baseAction.SPBonus * calculation.spellDmg
		end
	end
	--CORE: Powerbonus abilities, ferocious bite and enrage
	if action.PowerBonus and calculation.powerType == UnitPowerType("player") then
		local bonus = math_max(0,(UnitPower("player",calculation.powerType) - calculation.actionCost))
		if calculation.maxPower then bonus = math_min(calculation.maxPower, bonus ) end
		minDam = minDam + (bonus + calculation.extraPowerBonus) * (action.PowerBonus + (baseAction.PowerBonusAP or 0) * calculation.AP)
		maxDam = maxDam + (bonus + calculation.extraPowerBonus) * (action.PowerBonus + (baseAction.PowerBonusAP or 0) * calculation.AP)
		calculation.actionCost = calculation.actionCost + bonus
	end	
	
	--CORE: Calculate final min-max range
	local modDuration = baseDuration and eDuration > baseDuration and (1 + (eDuration - baseDuration) / baseDuration) or 1
	minDam = calculation.dmgM * minDam * modDuration + (baseDuration and 0 or calculation.dmgBonus)
	maxDam = calculation.dmgM * maxDam * modDuration + (baseDuration and 0 or calculation.dmgBonus)
	
	--CORE: Bleed Bonuses eg. Trauma
	if baseAction.Bleed then
		minDam = minDam * calculation.bleedBonus
		maxDam = maxDam * calculation.bleedBonus
	end
	
	--CORE: Show zero for not available abilities
	if baseAction.Weapon and baseAction.Weapon ~= mhType
	or baseAction.Offhand and baseAction.Offhand ~= ohType
	or baseAction.OffhandAttack and ohType == "None"
	or calculation.school == "Ranged" and rgType == "None"
	or calculation.unarmed and not baseAction.AutoAttack and not baseAction.NoWeapon and not baseAction.requiresForm
	or calculation.zero then
		calculation.zero = true
		minDam = 0
		maxDam = 0
	end
	
	avgHit = ((minDam + maxDam) / 2)
	
	--CORE: Crit calculation
	calculation.critPerc = math_max(0,math_min(100, calculation.critPerc))
	local critBonus = 0
	local critBonus_O = 0
	if not calculation.NoCrits then
		minCrit = minDam + minDam * calculation.critM
		maxCrit = maxDam + maxDam * calculation.critM
		avgCrit = (minCrit + maxCrit) / 2
		critBonus = (calculation.critPerc / 100) * avgHit * calculation.critM
		avgTotal = avgHit + critBonus
	else
		avgCrit = avgHit
		avgTotal = avgHit
	end
	
	--CORE: Crit calculation for off-hand and dual attack
	if (baseAction.DualAttack or baseAction.AutoAttack) and OffhandHasWeapon() then
		if baseAction.AutoAttack then
			hitDW = math_min(100,math_max(0,calculation.hit + calculation.hitPerc - 19))
			hitDWO = math_min(100,math_max(0,(calculation.hitO or calculation.hit) + calculation.hitPerc - 19))
		end
		minDam_O = calculation.dmgM * minDam_O
		maxDam_O = calculation.dmgM * maxDam_O
		avgHit_O = (minDam_O + maxDam_O)/2
		minCrit_O = minDam_O + minDam_O * calculation.critM
		maxCrit_O = maxDam_O + maxDam_O * calculation.critM
		avgCrit_O = (minCrit_O + maxCrit_O) / 2
		critBonus_O = (calculation.critPerc / 100) * avgHit_O * calculation.critM
		avgTotal_O = avgHit_O + critBonus_O
	end
	
	local extraDam, extraAvg, extraMax
	if calculation.extraDamage then
		local extra = 0
		local extra_O = 0
		local extraAvgTotal = 0
		local extraAvgTotal_O = 0
		local critBonus_Extra = 0
		local critBonus_Extra_O = 0	
		extraMax = 0
		--Extra effect chance is based on crit chance
		if calculation.extraChanceCrit then 
			calculation.extraChance = calculation.critPerc / 100 
		end	
		--Extra effect is derived from crit value (eg. Righteous Vengeance)
		if calculation.extraCrit then
			extra = avgCrit * calculation.extraCrit * (baseAction.BleedExtra and calculation.bleedBonus or 1)
			extraAvgTotal = extra * (calculation.extraCritChance or calculation.extraChance)
			extraMax = maxCrit * calculation.extraCrit * (baseAction.BleedExtra and calculation.bleedBonus or 1)
		end
		--Extra effect is derived from avg value
		--Main-hand (eg. Necrosis)
		if calculation.extraAvg then
			local bonus = (avgTotal / calculation.dmgM) * calculation.extraAvg * calculation.dmgM_Extra * (calculation.extraAvgM and calculation.mitigation or 1)
			extra = extra + bonus
			extraAvgTotal = extraAvgTotal + bonus * (calculation.extraAvgChance or calculation.extraChance)
			extraMax = extraMax + (maxCrit / calculation.dmgM) * calculation.extraAvg * calculation.dmgM_Extra * (calculation.extraAvgM and calculation.mitigation or 1)
		end
		--Off-hand (eg. Necrosis)
		if calculation.extraAvg_O then
			extra_O  = (avgTotal_O / calculation.dmgM) * calculation.extraAvg_O * calculation.dmgM_Extra * (calculation.extraAvgM_O and calculation.mitigation or 1)
			extraAvgTotal_O = extra_O * (calculation.extraAvgChance or calculation.extraChance)
			extraMax = extraMax + (maxCrit_O / calculation.dmgM) * calculation.extraAvg_O * calculation.dmgM_Extra * (calculation.extraAvgM_O and calculation.mitigation or 1)
		end
		--Extra effect is a multiplier of weapon damage
		--Main-hand (eg. Blood-Caked Blade, Deep Wounds)
		if calculation.extraWeaponDamage then 
			local min, max  = DrDamage:WeaponDamage(calculation, true)
			local bonus = calculation.extraWeaponDamage * 0.5 * (min + max) * (calculation.extraWeaponDamage_dmgM or calculation.dmgM_Extra) * (calculation.extraWeaponDamageM and calculation.mitigation or 1)
			extra = extra + bonus
			extraAvgTotal = extraAvgTotal + bonus * (calculation.extraWeaponDamageChance or calculation.extraChance)
			extraMax = extraMax + max * calculation.extraWeaponDamage * (calculation.extraWeaponDamage_dmgM or calculation.dmgM_Extra) * (calculation.extraWeaponDamageM and calculation.mitigation or 1)
		end
		--Off-hand (eg. Blood-Caked Blade, Deep Wounds)
		if calculation.extraWeaponDamage_O then 
			local _, _, min, max  = DrDamage:WeaponDamage(calculation, true)
			local bonus = calculation.extraWeaponDamage_O * 0.5 * (min + max) * (calculation.extraWeaponDamage_dmgM or calculation.dmgM_Extra) * (calculation.extraWeaponDamageM_O and calculation.mitigation or 1)
			extra_O = extra_O + bonus
			extraAvgTotal_O = extraAvgTotal_O + bonus * (calculation.extraWeaponDamageChance or calculation.extraChance)
			extraMax = extraMax + max * calculation.extraWeaponDamage * (calculation.extraWeaponDamage_dmgM or calculation.dmgM_Extra) * (calculation.extraWeaponDamageM_O and calculation.mitigation or 1)
		end
		--Module effect can crit
		if calculation.extra_canCrit then
			critBonus_Extra = extra * ((calculation.extra_critPerc or calculation.critPerc) / 100) * (calculation.extra_critM or calculation.critM)
			critBonus_Extra_O = extra_O * ((calculation.extra_critPerc or calculation.critPerc) /100) * (calculation.extra_critM or calculation.critM)
			extraMax = extraMax * (1 + (calculation.extra_critM or calculation.critM))
		end		
		--Main-hand extra damage effect from modules
		extraDam = (calculation.extra + calculation.extraDamage * calculation.AP) * (calculation.E_dmgM or calculation.dmgM_Extra) + calculation.extraDamBonus
		--Off-hand extra damage effect from modules (Poisons, Flametongue, Frostbrand)
		local extraDam_O = (calculation.extra_O + calculation.extraDamage_O * calculation.AP) * (calculation.E_dmgM or calculation.dmgM_Extra) + calculation.extraDamBonus_O
		--Extended duration for extra damage effect
		if calculation.E_eDuration and baseAction.E_eDuration and calculation.E_eDuration > baseAction.E_eDuration then
			local modDuration = 1 + (calculation.E_eDuration - baseAction.E_eDuration) / baseAction.E_eDuration
			extraDam = extraDam * modDuration
		end		
		--Extra effect can crit
		if calculation.E_canCrit then
			critBonus_Extra = critBonus_Extra + extraDam * ((calculation.E_critPerc or calculation.critPerc) / 100) * (calculation.E_critM or calculation.critM) * calculation.extraChance
			critBonus_Extra_O = critBonus_Extra_O + extraDam_O * ((calculation.E_critPerc_O or calculation.critPerc) / 100) * (calculation.E_critM or calculation.critM) * calculation.extraChance_O
			extraMax = extraMax + (extraDam + extraDam_O) * (1 + (calculation.E_critM or calculation.critM))
		else
			extraMax = extraMax + extraDam + extraDam_O
		end
		--Sums up main-hand average for DPS calculation
		avgTotal = avgTotal + extraDam * calculation.extraChance + extraAvgTotal + critBonus_Extra
		--Sums up off-hand average for DPS calculation
		avgTotal_O = avgTotal_O + extraDam_O * calculation.extraChance_O + extraAvgTotal_O + critBonus_Extra_O
		--Sums the average extra effect
		extraAvg = extraDam * calculation.extraChance + extraDam_O * calculation.extraChance_O + critBonus_Extra + critBonus_Extra_O + extraAvgTotal + extraAvgTotal_O
		--The amount of damage done on combined successful procs, non-crit
		extraDam = extraDam + extraDam_O + extra  + extra_O
		--AP bonus from extra module
		APmod = APmod + calculation.extraDamage + calculation.extraDamage_O
	end
	
	if not calculation.zero then
		--CORE: Per hit/tick calculation
		if hits then 
			perHit = avgTotal
		elseif baseAction.eDuration and baseAction.Ticks then
			ticks = eDuration / baseAction.Ticks
			perHit = (avgTotal - critBonus) / ticks
		elseif extraDam and baseAction.E_eDuration and baseAction.E_Ticks then
			ticks = calculation.E_eDuration / baseAction.E_Ticks
			perHit = extraDam / ticks
		elseif extraDam and calculation.extraTicks then
			ticks = calculation.extraTicks
			perHit = extraDam / ticks
		end
		
		--CORE: Attacks that replace next melee, eg. Cleave, Heroic Strike
		if baseAction.NextMelee then
			local min, max = DrDamage:WeaponDamage(calculation, true)
			baseAttack = calculation.dmgM * 0.5 * (min + max)
			avgTotalMod = avgTotal - critBonus - baseAttack
			critBonus = avgTotalMod * (calculation.critPerc / 100) * calculation.critM + baseAttack * (math_max(0,calculation.critPerc - GetCritChance()) / 100) * calculation.critM
			avgTotalMod = avgTotalMod + critBonus
		end

		--CORE: Multiple hit calculation
		if hits then
			avgTotal = avgTotal + (hits - 1) * perHit
			if baseAction.DualAttack then
				avgTotal_O = avgTotal_O + (hits - 1) * avgTotal_O
			end
			if avgTotalMod then
				avgTotalMod = avgTotalMod + (hits - 1) * perHit
			end
		end

		--CORE: Hit calculation
		if not baseAction.Unresistable then
			local hit, hitO = 100, 100
			local avoidance, avoidanceO = 0, 0
			local calc
			if settings.HitCalc_M or hitCalc then
				hit = hitDW or hitPerc
				hitO = hitDWO or hitPerc_O
				calc = true
			end
			if settings.Parry_M and calculation.parry then
				avoidance = math_max(0,calculation.parry - calculation.expertise * 0.25)
				avoidanceO = math_max(0,calculation.parry - calculation.expertise_O * 0.25)
				calc = true
			end
			if settings.Dodge_M and calculation.dodge then
				avoidance = avoidance + math_max(0,calculation.dodge - calculation.expertise * 0.25)
				avoidanceO = avoidanceO + math_max(0,calculation.dodge - calculation.expertise_O * 0.25)
				calc = true		
			end
			if calculation.glancing then
				avoidance = avoidance + calculation.glancing * calculation.glancingM
				avoidanceO = avoidanceO + calculation.glancing * calculation.glancingM
				calc = true
			end
			if calc then
				local tworoll = settings.TwoRoll_M and not baseAction.AutoAttack or baseAction.SpellHit and settings.TwoRoll
				avoidance = avoidance / 100
				avoidanceO = avoidanceO / 100

				avgTotal = math_max(0, avgTotal - (avgTotal - critBonus) * avoidance - (avgTotal - (tworoll and 0 or critBonus)) * (100 - hit) / 100)
				if avgTotalMod then
					--Hit penalty and bonus for converting a white attack to special attack (possible +hit increase when dual wielding)
					local bonus = OffhandHasWeapon() and (hitPerc - math_min(100,math_max(0,calculation.hit + calculation.hitPerc - 19))/100) or 0
					avgTotalMod = avgTotalMod - (avgTotalMod - critBonus) * avoidance - (avgTotalMod - (tworoll and 0 or critBonus)) * (100 - hit) / 100 + baseAttack * bonus
				end
				if OffhandHasWeapon() then
					avgTotal_O = math_max(0, avgTotal_O - (avgTotal_O - critBonus_O) * avoidanceO - (avgTotal - (tworoll and 0 or critBonus_O)) * (100 - hitO) / 100)
				end
			end
		end

		--CORE: Windfury calculation
		if calculation.WindfuryBonus then
			local min, max = DrDamage:WeaponDamage(calculation, true)
			local bspd = DrDamage:GetWeaponSpeed()
			local avgWf = calculation.dmgM * (calculation.WindfuryDmgM or 1) * 2 * ((min+max)/2 + calculation.WindfuryBonus / 14 * bspd)
			local avgTotalWf =  avgWf * (1 + calculation.critM * calculation.critPerc / 100) * (hitPerc / 100) * calculation.WindfuryChance * ((hitDW or hitPerc) / 100)
			extraDam = (extraDam or 0) + avgWf
			extraAvg = (extraAvg or 0) + avgTotalWf
			extraMax = (extraMax or 0) + avgWf * (1 + calculation.critM)
			avgTotal = avgTotal + avgTotalWf
		end
		if calculation.WindfuryBonus_O then
			local _, _, min, max = DrDamage:WeaponDamage(calculation, true)
			local _, bspd = DrDamage:GetWeaponSpeed()
			local avgWf_O = calculation.dmgM * (calculation.WindfuryDmgM or 1) * 2 * ((min+max)/2 + calculation.WindfuryBonus_O / 14 * bspd)
			local avgTotalWf_O = avgWf_O * (1 + calculation.critM * calculation.critPerc / 100) * (hitPerc_O / 100) * calculation.WindfuryChance * ((hitDWO or hitPerc_O) / 100)
			extraDam = (extraDam or 0) + avgWf_O
			extraAvg = (extraAvg or 0) + avgTotalWf_O
			extraMax = (extraMax or 0) + avgWf_O * (1 + calculation.critM)		
			avgTotal_O = avgTotal_O + avgTotalWf_O
		end		
	else
		avgTotal = 0
		avgTotal_O = 0
	end	
	
	local avgCombined = (avgTotalMod or avgTotal) + avgTotal_O
	
	--CORE: DPS calculation
	local DPS, DPSCD
	if baseAction.AutoShot then
		DPS = avgTotal / math_max(0.5, (UnitRangedDamage("player")))
	elseif baseAction.AutoAttack or baseAction.WeaponDPS then
		if hits then DPS = (avgTotal / hits) / spd 
		else DPS = avgTotal / spd end
		
		if ospd then
			DPS = DPS + avgTotal_O / ospd
		end
	elseif baseAction.DPSrg then
		DPS = avgTotal / (UnitRangedDamage("player"))
	else
		if eDuration > 0 then
			DPS = avgCombined / eDuration
		elseif extraDam and calculation.E_eDuration then
			DPS = avgCombined / calculation.E_eDuration
		end
		if calculation.cooldown > 0 then
			if baseAction.NextMelee then
				DPSCD = DrD_Round(avgCombined / (calculation.cooldown + spd * select(2,math_modf(calculation.cooldown / spd))), 1)
			else	
				DPSCD = DrD_Round(avgCombined / calculation.cooldown,1)
			end
		end
		if baseAction.SpamDPS then
			DPS = avgCombined / baseAction.SpamDPS
		end
	end
	local extraDPS
	if calculation.extra_DPS and DPS then
		extraDPS = (calculation.E_dmgM or calculation.dmgM) * (calculation.extraStacks_DPS or 1) * (calculation.extra_DPS + calculation.extraDamage_DPS * calculation.AP) / calculation.extraDuration_DPS
		DPS = DPS + extraDPS
	end
	if calculation.procPerc then
		DPS = DPS * calculation.procPerc
	end
	if not nextCalc then
		DrD_ClearTable( CalculationResults )
	
		CalculationResults.Avg = 	math_floor(avgHit + 0.5)
		CalculationResults.AvgTotal = 	math_floor(((avgTotalMod and (avgTotal + avgTotal_O)) or avgCombined) + 0.5)
		CalculationResults.Min = 	math_floor(minDam)
		CalculationResults.Max = 	math_ceil(maxDam)
		CalculationResults.AvgCrit = 	math_floor(avgCrit + 0.5)

		if not calculation.NoCrits then
			CalculationResults.MinCrit = 	math_floor(minCrit)
			CalculationResults.MaxCrit = 	math_ceil(maxCrit)
			CalculationResults.CritM =	DrD_Round( 100 + calculation.critM * 100, 2)			
		else
			CalculationResults.MinCrit = 	CalculationResults.Min
			CalculationResults.MaxCrit = 	CalculationResults.Max		
		end

		if (tooltip or settings.DisplayType_M == "DPM" or settings.DisplayType_M == "PowerCost") and not baseAction.AutoShot and not baseAction.AutoAttack and powerTypes[calculation.powerType] then
			CalculationResults.PowerType = calculation.powerType
			CalculationResults.PowerCost = 0
			
			if baseAttack and calculation.powerType == 1 then
				calculation.actionCost = calculation.actionCost + DrDamage:GetRageGain(baseAttack, calculation) * calculation.rageBonus
			end
			if calculation.freeCrit > 0 then
				calculation.actionCost = calculation.actionCost - calculation.actionCost * calculation.freeCrit * (calculation.critPerc / 100) * (hitPerc / 100)
			end
			if calculation.actionCost <= 0 then
				CalculationResults.DPM = "\226\136\158"
			else
				if calculation.maxCost then
					calculation.actionCost = math_min(calculation.maxCost, calculation.actionCost)
				end
				CalculationResults.DPM = DrD_Round(avgCombined / calculation.actionCost, 1)
				CalculationResults.PowerCost = math_floor(calculation.actionCost + 0.5)
			end
		end
		if tooltip then
			CalculationResults.Hit = 	DrD_Round(hitDW or hitPerc, 2)
			CalculationResults.AP = 	calculation.AP		
			CalculationResults.Ranged =	calculation.ranged
			CalculationResults.DmgM = 	DrD_Round(calculation.dmgM_Display, 2)
			CalculationResults.APM = 	DrD_Round(APmod, 3)
			
			if settings.Parry_M and calculation.parry then
				CalculationResults.Parry = math_max(0,calculation.parry - calculation.expertise * 0.25)
			end
			if settings.Dodge_M and calculation.dodge then
				CalculationResults.Dodge = math_max(0,calculation.dodge - calculation.expertise * 0.25)
			end
			if settings.Glancing_M and calculation.glancing then
				CalculationResults.Glancing = calculation.glancing
			end		
			if calculation.mitigation < 1 then
				CalculationResults.Mitigation = DrD_Round((1 - calculation.mitigation) * 100, 2)
			end
			if not calculation.NoCrits then
				CalculationResults.Crit = 	DrD_Round(calculation.critPerc, 2)
			end
			if DPS then
				CalculationResults.DPS = DrD_Round(DPS,1)
				if eDuration > 0 then
					CalculationResults.DPS_Duration = eDuration
				elseif calculation.E_eDuration then
					CalculationResults.DPS_Duration = calculation.E_eDuration
				end
			end
			if DPSCD then
				CalculationResults.DPSCD = DPSCD
			end
			if avgHit_O then
				CalculationResults.AvgTotalM =	math_floor(avgTotal + 0.5)
				CalculationResults.AvgO = 	math_floor(avgHit_O + 0.5)
				CalculationResults.MinO = 	math_floor(minDam_O)
				CalculationResults.MaxO = 	math_ceil(maxDam_O)
				CalculationResults.HitO =	DrD_Round(hitDWO or hitPerc_O, 2)
				CalculationResults.MinCritO = 	math_floor(minCrit_O)
				CalculationResults.MaxCritO = 	math_ceil(maxCrit_O)
				CalculationResults.AvgCritO = 	math_floor(avgCrit_O + 0.5)
				CalculationResults.AvgTotalO =  math_floor(avgTotal_O + 0.5)
			end
			if extraDam then
				CalculationResults.ExtraName =	calculation.extraName
				CalculationResults.Extra = 	math_floor(extraDam + 0.5)
				CalculationResults.ExtraAvg = 	math_floor(extraAvg + 0.5)
				CalculationResults.ExtraMax = 	math_floor(extraMax + 0.5)
			end
			if extraDPS then
				CalculationResults.ExtraDPS = DrD_Round( extraDPS, 1)
				CalculationResults.ExtraNameDPS = calculation.extraName_DPS
			end
			if baseAction.SPBonus and calculation.spellDmg > 0 then 
				CalculationResults.SpellDmg = math_floor( calculation.spellDmg + 0.5 )
				CalculationResults.SpellDmgM = DrD_Round( baseAction.SPBonus, 3 )
			end 
			if perHit and ticks then
				if not calculation.NoCrits and not baseAction.E_eDuration and not calculation.extraTicks or baseAction.E_eDuration and calculation.E_canCrit then
					CalculationResults.PerCrit = math_floor( perHit * (1 + (calculation.E_critM or calculation.critM)) + 0.5 )
					CalculationResults.Crits = math_floor( ticks * (calculation.critPerc / 100) + 0.5 )
					ticks = ticks - CalculationResults.Crits
				end			
				CalculationResults.Hits = 	ticks or hits
				CalculationResults.PerHit =	DrD_Round(perHit, 1)
			end
			if calculation.procPerc then CalculationResults.ProcChance = DrD_Round(calculation.procPerc * 100,2) end
		end
	end
	return avgCombined, CalculationResults[settings.DisplayType_M]
end


function DrDamage:MeleeTooltip( frame, name, rank )
	self:MeleeCalc(name, rank, true)
	
	local baseSpell = spellInfo[name][0]
	if type(baseSpell) == "function" then baseSpell, _, name = baseSpell() end
	
	frame:AddLine(" ")
	
	local r, g, b = 1, 0.82745098, 0
	
	if DrD_MatchData( baseSpell.School, "Judgement" ) or name ~= frame:GetSpell() then
		frame:AddLine( name, r, g, b )
		frame:AddLine(" ")
	end	

	if not settings.DefaultColor then
		r, g, b = 0, 0.7, 0
	end

	if settings.Coeffs_M then
		frame:AddDoubleLine(L["Coeffs"] .. ":", (CalculationResults.SpellDmg and (CalculationResults.SpellDmgM .. "*" .. CalculationResults.SpellDmg .. "/") or "") .. CalculationResults.APM .. "*" .. CalculationResults.AP, 1, 1, 1, r, g, b  )
		frame:AddDoubleLine(L["Multiplier:"], (CalculationResults.DmgM * 100) .. "%", 1, 1, 1, r, g, b  )
		if CalculationResults.CritM then
			frame:AddDoubleLine(L["Crit Multiplier:"], CalculationResults.CritM .. "%", 1, 1, 1, r, g, b  )
		end		
		if CalculationResults.ProcChance then
			frame:AddDoubleLine(L["Proc Chance:"], CalculationResults.ProcChance .. "%", 1, 1, 1, r, g, b )
		end
		if CalculationResults.Mitigation then
			frame:AddDoubleLine(L["Armor:"], CalculationResults.Mitigation .. "%", 1, 1, 1, r, g, b )
		end
		if CalculationResults.Dodge or CalculationResults.Parry or CalculationResults.Glancing then
			frame:AddDoubleLine((CalculationResults.Dodge and L["Dodge"] or "") .. (CalculationResults.Parry and (CalculationResults.Dodge and ("/" .. L["Parry"]) or L["Parry"]) or "") .. (CalculationResults.Glancing and ((CalculationResults.Dodge or CalculationResults.Parry) and ("/" .. L["Glancing"]) or L["Glancing"]) or "") .. ":", (CalculationResults.Dodge and (CalculationResults.Dodge .. "%") or "") .. (CalculationResults.Parry and (CalculationResults.Dodge and ("/" .. CalculationResults.Parry .. "%") or (CalculationResults.Parry .. "%")) or "") .. (CalculationResults.Glancing and ((CalculationResults.Dodge or CalculationResults.Parry) and ("/" .. CalculationResults.Glancing .. "%") or (CalculationResults.Glancing .. "%")) or ""), 1, 1, 1, r, g, b )
		end
	end

	if settings.DispCrit_M and CalculationResults.Crit then
		frame:AddDoubleLine(L["Crit:"], CalculationResults.Crit .. "%", 1, 1, 1, r, g, b )
	end

	if settings.DispHit_M and not baseSpell.Unresistable then
		frame:AddDoubleLine(L["Hit:"], CalculationResults.Hit .. "%", 1, 1, 1, r, g, b )
		if CalculationResults.HitO then
			frame:AddDoubleLine(L["Off-Hand"] .. " " .. L["Hit:"], CalculationResults.HitO .. "%", 1, 1, 1, r, g, b )
		end
	end

	if not settings.DefaultColor then
		r, g, b = 0.8, 0.8, 0.9
	end
	
	if settings.AvgHit_M or settings.AvgCrit_M then
		if CalculationResults.AvgO then
			frame:AddLine(L["Main Hand:"])
		end
	end
	if settings.AvgHit_M then
		frame:AddDoubleLine(L["Avg:"], CalculationResults.Avg .. " (".. CalculationResults.Min .."-".. CalculationResults.Max ..")", 1, 1, 1, r, g, b )
	end
	if settings.AvgCrit_M and CalculationResults.Crit then
		frame:AddDoubleLine(L["Avg Crit:"], CalculationResults.AvgCrit .. " (".. CalculationResults.MinCrit .."-".. CalculationResults.MaxCrit ..")", 1, 1, 1, r, g, b )
	end
	
	if settings.Total_M and CalculationResults.AvgTotal then
		frame:AddDoubleLine(L["Avg Total:"], (CalculationResults.AvgTotalM or CalculationResults.AvgTotal), 1, 1, 1, r, g, b)
	end	
	
	if CalculationResults.AvgO and (settings.AvgHit_M or settings.AvgCrit_M) then
		frame:AddLine(L["Off-Hand"] .. ":")
	end	
	
	if baseSpell.DualAttack and settings.Extra_M or baseSpell.AutoAttack then
		if CalculationResults.AvgO then
			if settings.AvgHit_M then
				frame:AddDoubleLine(L["Avg:"], CalculationResults.AvgO .. " (".. CalculationResults.MinO .."-".. CalculationResults.MaxO ..")", 1, 1, 1, r, g, b )
			end
			if settings.AvgCrit_M and CalculationResults.AvgCritO then
				frame:AddDoubleLine(L["Avg Crit:"], CalculationResults.AvgCritO .. " (".. CalculationResults.MinCritO .."-".. CalculationResults.MaxCritO ..")", 1, 1, 1, r, g, b )
			end
			if settings.Total_M and CalculationResults.AvgTotalO then -- and CalculationResults.AvgTotalO > CalculationResults.AvgO then
				frame:AddDoubleLine(L["Avg Total:"], CalculationResults.AvgTotalO, 1, 1, 1, r, g, b  )
			end		
		end
	end
	if settings.Total_M and CalculationResults.AvgTotalO then
		frame:AddLine("-")
	end
	if settings.Extra_M then
		if CalculationResults.Extra then
			if CalculationResults.ExtraAvg ~= CalculationResults.Extra then
				frame:AddDoubleLine((CalculationResults.ExtraName or L["Additional"]) .. " " .. L["Avg/Proc:"], CalculationResults.ExtraAvg .. "/" .. CalculationResults.Extra, 1, 1, 1, r, g, b)
				frame:AddDoubleLine((CalculationResults.ExtraName or L["Additional"]) .. " " .. L["Max"] ..":", CalculationResults.ExtraMax, 1, 1, 1, r, g, b)
			else
				frame:AddDoubleLine((CalculationResults.ExtraName or L["Additional"]) .. ":", CalculationResults.Extra, 1, 1, 1, r, g, b)
			end
		end		
	end
	if settings.Ticks_M then
		if CalculationResults.Hits and CalculationResults.PerHit then
			frame:AddDoubleLine(L["Dot"] .. " " .. L["Hits:"], CalculationResults.Hits .. "x ~" .. CalculationResults.PerHit, 1, 1, 1, r, g, b ) 
		end
		if CalculationResults.PerCrit and CalculationResults.Crits > 0 then
			frame:AddDoubleLine(L["Dot"] .. " " .. L["Crits:"], CalculationResults.Crits .. "x ~" .. CalculationResults.PerCrit, 1, 1, 1, r, g, b )
		end
	end
	if settings.Total_M and CalculationResults.AvgTotalO then
		frame:AddDoubleLine(L["Combined Total:"], CalculationResults.AvgTotal, 1, 1, 1, r, g, b  )
	end
	

	if not settings.DefaultColor then
		r, g, b = 0.3, 0.6, 0.5
	end
	
	local bType
	if CalculationResults.Ranged then
		bType = L["RAP"]
	else
		bType = L["AP"]
	end
	
	if not baseSpell.NoNext and settings.Next_M then
		local critA, hitA, apA, sdA
		
		if CalculationResults.NextAP then
			frame:AddDoubleLine("+100 " .. bType .. ":", ((CalculationResults.NextAP > 0) and "+" or "") .. CalculationResults.NextAP, 1, 1, 1, r, g, b )
			if CalculationResults.NextAP > 0.15 then
				apA = DrD_Round(CalculationResults.AvgTotal/ CalculationResults.NextAP, 1)
			end
		end
		if CalculationResults.NextSpellDmg then
			frame:AddDoubleLine("+10 " .. L["SP"] .. ":", "+" .. CalculationResults.NextSpellDmg, 1, 1, 1, r, g, b )
			if CalculationResults.NextSpellDmg > 0.15 then
				sdA = DrD_Round(CalculationResults.AvgTotal * 0.1 / CalculationResults.NextSpellDmg, 1)
			end
		end		
		if CalculationResults.NextCrit then
			frame:AddDoubleLine("+1% " .. L["Crit"] .. " (" .. self:GetRating("Crit") .. "):", ((CalculationResults.NextCrit > 0) and "+" or "") .. CalculationResults.NextCrit, 1, 1, 1, r, g, b )
			if CalculationResults.NextCrit > 0.15 then
				critA = DrD_Round(CalculationResults.AvgTotal * 0.01 / CalculationResults.NextCrit * self:GetRating("Crit", nil, true ), 1 )
			end
		end
		if CalculationResults.NextHit then
			frame:AddDoubleLine("+1% " .. L["Hit"] .. " (" .. self:GetRating("MeleeHit") .. "):", ((CalculationResults.NextHit > 0) and "+" or "") .. CalculationResults.NextHit, 1, 1, 1, r, g, b )
			if CalculationResults.NextHit > 0.15 then
				hitA = DrD_Round(CalculationResults.AvgTotal * 0.01 / CalculationResults.NextHit * self:GetRating("MeleeHit", nil, true), 1 )
			end  										
		end
		if critA or hitA or apA or sdA then
			frame:AddDoubleLine("+1% " .. L["Total"] .. " (" .. ((critA and (L["Cr"] .. ((hitA or apA) and "/" or ""))) or "") .. ((hitA and (L["Ht"] .. (apA and "/" or ""))) or "") .. (apA and bType or "") .. ((sdA and "/+dmg") or "") .. "):", ((critA and (critA .. ((hitA or apA) and "/" or ""))) or "") .. ((hitA and (hitA .. (apA and "/" or ""))) or "") .. (apA or "") .. (sdA and ("/" .. sdA) or ""), 1, 1, 1, r, g, b )
		end		
		if CalculationResults.NextExpertise then
			frame:AddDoubleLine("+1 " .. L["Expertise"], ((CalculationResults.NextExpertise > 0) and "+" or "") .. CalculationResults.NextExpertise, 1, 1, 1, r, g, b )									
		end		
	end

	if not settings.DefaultColor then
		r, g, b = 0.8, 0.1, 0.1
	end
	
	if not baseSpell.NoDPS and settings.DPS_M then
		if settings.Extra_M and CalculationResults.ExtraDPS then
			frame:AddDoubleLine(L["DPS"] .. " (" .. CalculationResults.ExtraNameDPS .. "):", CalculationResults.ExtraDPS, 1, 1, 1, r, g, b)
		end	
		if CalculationResults.DPS then
			frame:AddDoubleLine(L["DPS"] .. ((baseSpell.DPSrg and " " .. L["(1/wspd):"]) or (CalculationResults.DPS_Duration and " (" .. L["over"] .. " " .. CalculationResults.DPS_Duration .. "s):") or ":"), CalculationResults.DPS, 1, 1, 1, r, g, b )
			if baseSpell.Stacks then
				frame:AddDoubleLine(L["DPS"] .. " (x" .. baseSpell.Stacks .. ")", baseSpell.Stacks * CalculationResults.DPS, 1, 1, 1, r, g, b )
			end
		end
		if CalculationResults.DPSCD then
			frame:AddDoubleLine(L["DPS (CD):"], CalculationResults.DPSCD, 1, 1, 1, r, g, b )
		end
	end

	if CalculationResults.DPM and not baseSpell.NoDPM and settings.DPM_M then
		frame:AddDoubleLine( L["Dmg"] .. "/" .. powerTypes[CalculationResults.PowerType], CalculationResults.DPM, 1, 1, 1, r, g, b )
	end

	frame:Show()
end